# -*- coding:utf-8 -*-
# @File       :   assertOpt.py
# @Author     :   LINING
# @Time       :   2024/7/24 10:32
# @Description : 断言
import re
import ast
from Handle.handle_log import log
from playwright.sync_api import expect
from assertpy import assertpy
from Core.pageOpt import Page


class EleAssert:
    """
    使用元素或页面断言，自带断言方法
    """
    def __init__(self, locator):
        """
        :param locator:元素，或page
        """
        self.locator = locator
        self.page = Page(self.locator)

    def assertions(self, assert_type, text=None, value=None):
        """
        :param assert_type: 断言类型
        :param text: 文本内容,数量
        :param value: 类型
        :return:
        """
        self.assert_type = assert_type
        self.text = text
        # 断言时间默认5秒
        timeout = 5000
        assert_fail = ''
        try:
            if self.assert_type in ['元素存在', 'attached']:
                # 元素存在于dom节点
                assert_fail = '元素存在，to_be_attached断言失败'
                expect(self.locator).to_be_attached(timeout=timeout)
            elif self.assert_type in ['元素选中', 'checked']:
                # 要有checked属性，复选框选中
                assert_fail = '元素选中，to_be_checked断言失败'
                expect(self.locator).to_be_checked(timeout=timeout)
            elif self.assert_type in ['元素禁用', 'disabled']:
                # 要有disabled属性，元素被禁用
                assert_fail = '元素禁用，to_be_disabled断言失败'
                expect(self.locator).to_be_disabled(timeout=timeout)
            elif self.assert_type in ['元素可编辑', 'editable']:
                # 元素可编辑
                assert_fail = '元素可编辑，to_be_editable断言失败'
                expect(self.locator).to_be_editable(timeout=timeout)
            elif self.assert_type in ['容器为空', 'empty']:
                # 容器为空
                assert_fail = '容器为空，to_be_empty断言失败'
                expect(self.locator).to_be_empty(timeout=timeout)
            elif self.assert_type in ['元素启用', 'enabled']:
                # 元素需要带有disabled属性
                assert_fail = '元素启用，to_be_enabled断言失败'
                expect(self.locator).to_be_enabled(timeout=timeout)
            elif self.assert_type in ['元素获得焦点', 'focused']:
                assert_fail = '元素获得焦点，to_be_focused断言失败'
                expect(self.locator).to_be_focused(timeout=timeout)
            elif self.assert_type in ['元素隐藏', 'hidden']:
                assert_fail = '元素隐藏，to_be_hidden断言失败'
                expect(self.locator).to_be_hidden(timeout=timeout)
            elif self.assert_type in ['元素可视', 'in_viewport']:
                # 元素出现在屏幕上，可以看到
                assert_fail = '元素可视，to_be_in_viewport断言失败'
                expect(self.locator).to_be_in_viewport(timeout=timeout)
            elif self.assert_type in ['元素可见', 'visible']:
                assert_fail = '元素可见，to_be_visible断言失败'
                expect(self.locator).to_be_visible(timeout=timeout)
            elif self.assert_type in ['元素包含文字', 'contain_text']:
                # 元素包含文本
                assert_fail = '元素包含文字，to_have_contain_text()断言失败'
                expect(self.locator).to_have_contain_text(self.text, timeout=timeout)
            elif self.assert_type in ['包含描述', 'have_accessible_description']:
                # 元素包含可访问的描述
                assert_fail = '包含描述，to_have_accessible_description断言失败'
                expect(self.locator).to_have_accessible_description(self.text, timeout=timeout)
            elif self.assert_type in ['包含名字', 'have_accessible_name']:
                # 元素包含名字
                assert_fail = '元素包含名字，to_have_accessible_name断言失败'
                expect(self.locator).to_have_accessible_name(self.text, timeout=timeout)
            elif self.assert_type in ['包含属性', 'have_attribute']:
                # 元素包含属性
                assert_fail = '元素包含属性，to_have_attribute断言失败'
                expect(self.locator).to_have_attribute(self.text, value, timeout=timeout)
            elif self.assert_type in ['包含class', 'have_class']:
                # 元素包含class
                assert_fail = '元素包含文字，to_have_class断言失败'
                expect(self.locator).to_have_class(self.text, timeout=timeout)
            elif self.assert_type in ['元素数量', 'have_count']:
                # 元素数量
                assert_fail = '元素数量，to_have_count断言失败'
                expect(self.locator).to_have_count(self.text, timeout=timeout)
            elif self.assert_type in ['包含css', 'have_css']:
                # 元素包含css,text传name,type传value
                assert_fail = '元素包含文字，to_have_css断言失败'
                expect(self.locator).to_have_css(self.text, value, timeout=timeout)
            elif self.assert_type in ['包含id', 'have_id']:
                # 元素包含id
                assert_fail = '元素包含id，to_have_id断言失败'
                expect(self.locator).to_have_id(self.text, timeout=timeout)
            elif self.assert_type in ['包含js属性', 'js_property']:
                # 元素包含js属性,text传name,type传value
                assert_fail = '元素包含js属性，to_js_property断言失败'
                expect(self.locator).to_have_js_property(self.text, value, timeout=timeout)
            elif self.assert_type in ['包含标签', 'have_role']:
                # 元素包含标签
                assert_fail = '元素包含标签，to_have_role断言失败'
                expect(self.locator).to_have_role(self.text, timeout=timeout)
            elif self.assert_type in ['表单包含文本', 'have_text']:
                # 表单元素是否具有特定文本内容
                assert_fail = '表单元素包含文本，to_have_text断言失败'
                expect(self.locator).to_have_text(self.text, timeout=timeout)
            elif self.assert_type in ['表单包含值', 'have_value']:
                # 表单元素是否具有特定值
                assert_fail = '表单包含值，to_have_value断言失败'
                expect(self.locator).to_have_value(self.text, timeout=timeout)
            elif self.assert_type in ['表单包含值集合', 'have_values']:
                # 表单元素是否具有特定值集合,text传列表
                assert_fail = '表单包含值集合，to_have_values断言失败'
                expect(self.locator).to_have_values(self.text, timeout=timeout)
            elif self.assert_type in ['页面标题包含', 'have_title']:
                # 页面标题包含，locator传page
                assert_fail = '页面标题包含，to_have_title断言失败'
                expect(self.locator).to_have_title(self.text, timeout=timeout)
            elif self.assert_type in ['页面url包含', 'have_url']:
                # 页面url包含，locator传page
                assert_fail = '页面url包含，to_have_url断言失败'
                expect(self.locator).to_have_url(url_or_reg_exp=self.text, timeout=timeout)
            log.log_info(f'{self.assert_type}:断言成功')
        except Exception as e:
            log.log_error(assert_fail+'：'+repr(e))
            raise e


class TextAssert:
    """使用文本断言"""
    def __init__(self, actual_result, position, excepted_result):
        """
        :param actual_result: 实际结果
        :param position: 比较方法
        :param excepted_result: 期望结果
        """
        self.comparator = position
        self.actual_result = actual_result
        self.excepted_result = excepted_result

    def compare(self):
        assFailMsg = ""
        try:
            if self.comparator in ["equal", "equals", "相等", "等于", "字符相等"]:  # 等于
                assFailMsg = '断言：实际值({})与预期值({}) 字符相等，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_equal_to(self.excepted_result)
            elif self.comparator in ["equals_list", "列表相等"]:  # 列表相同，包括列表顺序也相同
                assFailMsg = '断言：实际值({})与预期值({}) 列表相等，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.str2list(self.actual_result)).is_equal_to(
                    TextAssert.str2list(self.excepted_result))
            elif self.comparator in ["equals_dict", "字典相等"]:  # 字典相同
                assFailMsg = '断言：实际值({})与预期值({}) 字典相等，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.str2dict(self.actual_result)).is_equal_to(
                    TextAssert.str2dict(self.excepted_result))
            elif self.comparator in ["equals(number)", "数字相等", "数值相等"]:  # 数字等于
                assFailMsg = '断言：实际值({})与预期值({}) 数值相等，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.str2num(self.actual_result)).is_equal_to(
                    TextAssert.str2num(self.excepted_result))
            elif self.comparator in ["equalIgnoreCase", "相等(忽略大小写)"]:  # 忽略大小写等于
                assFailMsg = '断言：实际值({})与预期值({}) 相等(忽略大小写)，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_equal_to_ignoring_case(self.excepted_result)
            elif self.comparator in ["notEqual", "does not equal", "不等于"]:  # 不等于
                assFailMsg = '断言：实际值({}) 不等于 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_not_equal_to(self.excepted_result)
            elif self.comparator in ["contains", "包含"]:  # 字符串包含该字符
                assFailMsg = '断言：实际值({}) 包含 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.to_str(self.actual_result)).contains((self.excepted_result))
            elif self.comparator in ["notContains", "does no contains", "不包含"]:  # 字符串不包含该字符
                assFailMsg = '断言：实际值({}) 不包含 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).does_not_contain(*TextAssert.str2list(self.excepted_result))
            elif self.comparator in ["containsOnly", "仅包含"]:  # 字符串仅包含该字符
                assFailMsg = '断言：实际值({}) 仅包含 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).contains_only(*TextAssert.str2list(self.excepted_result))
            elif self.comparator in ["isNone", "none/null"]:  # 为none或null
                assFailMsg = '断言：实际值({}) 为none或null，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_none()
            elif self.comparator in ["notEmpty", "is not empty", "不为空"]:  # 不为空
                assFailMsg = '断言：实际值({}) 不为空，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_not_empty()
            elif self.comparator in ["empty", "is empty", "为空"]:  # 为空
                assFailMsg = '断言：实际值({}) 为空，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_empty()
            elif self.comparator in ["isTrue", "true"]:  # 是true
                assFailMsg = '断言：实际值({}) 是true，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_true()
            elif self.comparator in ["isFalse", "false"]:  # 是false
                assFailMsg = '断言：实际值({}) 是false，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_false()
            elif self.comparator in ["isStrType", "字符串"]:  # 是str的类型
                assFailMsg = '断言：实际值({}) 是字符串，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_type_of(str)
            elif self.comparator in ["isIntType", "整数"]:  # 是int的类型
                assFailMsg = '断言：实际值({}) 是整数，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_type_of(int)
            elif self.comparator in ["isFloatType", "浮点数"]:  # 是浮点的类型
                assFailMsg = '断言：实际值({}) 是浮点数，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_type_of(float)
            elif self.comparator in ["isInt", "is a number", "仅含数字"]:  # 字符串中仅含有数字
                assFailMsg = '断言：实际值({}) 仅含数字，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_digit()
            elif self.comparator in ["isLetter", "仅含字母"]:  # 字符串中仅含有字母
                assFailMsg = '断言：实际值({}) 仅含字母，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_alpha()
            elif self.comparator in ["isLower", "小写"]:  # 是小写的
                assFailMsg = '断言：实际值({}) 是小写的，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_lower()
            elif self.comparator in ["isUpper", "大写"]:  # 是大写的
                assFailMsg = '断言：实际值({}) 是大写的，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_upper()
            elif self.comparator in ["startWith", "开头是"]:  # 字符串以该字符开始
                assFailMsg = '断言：实际值({}) 开头是 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).starts_with(self.excepted_result)
            elif self.comparator in ["endWith", "结尾是"]:  # 字符串以该字符结束
                assFailMsg = '断言：实际值({}) 结尾是 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).ends_with(self.excepted_result)
            elif self.comparator in ["isIn", "has item", "包含对象", "被包含"]:  # 在这几个字符串中
                assFailMsg = '断言：实际值({}) 被包含在 预期值({}) 列表中，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_in(*TextAssert.str2list(self.excepted_result))
            elif self.comparator in ["isNotIn", "不被包含"]:  # 不在这几个字符串中
                assFailMsg = '断言：实际值({}) 不被包含在 预期值({}) 列表中，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_not_in(*TextAssert.str2list(self.excepted_result))
            elif self.comparator in ["isNotZero", "非0"]:  # 不是0
                assFailMsg = '断言：实际值({}) 不是0，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.str2num(self.actual_result)).is_not_zero()
            elif self.comparator in ["isZero", "为0"]:  # 是0
                assFailMsg = '断言：实际值({}) 是0，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.str2num(self.actual_result)).is_zero()
            elif self.comparator in ["isPositive", "正数"]:  # 是正数
                assFailMsg = '断言：实际值({}) 是正数，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_positive()
            elif self.comparator in ["isNegative", "负数"]:  # 是负数
                assFailMsg = '断言：实际值({}) 是负数，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_negative()
            elif self.comparator in ["isGreaterThan", " 大于"]:  # 大于
                assFailMsg = '断言：实际值({}) 大于 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_greater_than(TextAssert.str2num(self.excepted_result))
            elif self.comparator in ["isGreaterThanOrEqualTo", "greater than or equal", ">=", " 大于等于"]:  # 大于等于
                assFailMsg = '断言：实际值({}) 大于等于 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_greater_than_or_equal_to(
                    TextAssert.str2num(self.excepted_result))
            elif self.comparator in ["isLessThan", " 小于"]:  # 小于
                assFailMsg = '断言：实际值({}) 小于 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_less_than(TextAssert.str2num(self.excepted_result))
            elif self.comparator in ["isLessThanOrEqualTo", "less than or equal", "<=", " 小于等于"]:  # 小于等于
                assFailMsg = '断言：实际值({}) 小于等于 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_less_than_or_equal_to(
                    TextAssert.str2num(self.excepted_result))
            elif self.comparator in ["isBetween", " 在...之间"]:  # 在...之间
                assFailMsg = '断言：实际值({}) 在 预期值({}) 之间，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_between(*TextAssert.str2list(self.excepted_result))
            elif self.comparator in ["isCloseTo", " 接近于"]:  # 接近于
                assFailMsg = '断言：实际值({}) 接近于 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(self.actual_result).is_close_to(*TextAssert.str2list(self.excepted_result))
            elif self.comparator in ["listLen_equal", "列表长度相等"]:  # 列表长度相等
                assFailMsg = '断言：实际值({}) 列表长度相等 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.list_len(self.actual_result)).is_equal_to(
                    TextAssert.str2num(self.excepted_result))
            elif self.comparator in ["listLen_isGreaterThan", "列表长度大于"]:  # 列表长度大于
                assFailMsg = '断言：实际值({}) 列表长度大于 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.list_len(self.actual_result)).is_greater_than(
                    TextAssert.str2num(self.excepted_result))
            elif self.comparator in ["listLen_isLessThan", "列表长度小于"]:  # 列表长度小于
                assFailMsg = '断言：实际值({}) 列表长度小于 预期值({})，断言失败！！！'.format(self.actual_result, self.excepted_result)
                assertpy.assert_that(TextAssert.list_len(self.actual_result)).is_less_than_or_equal_to(
                    TextAssert.str2num(self.excepted_result))
            else:
                raise AssertionTypeNotExist('没有{}该断言类型'.format(self.comparator))
            assert True
        except AssertionError:
            log.log_error(assFailMsg)
            assert False

    @staticmethod
    def str2num(value):
        if type(value) == int or type(value) == float:
            return value
        if value is None or len(value) == 0:
            return None
        elif re.fullmatch(r'-?[0-9]*\.?[0-9]*', value) is not None:
            if '.' in value:
                return float(value)
            else:
                return int(value)
        else:
            return value

    @staticmethod
    def str2list(value):  # 适配期望值为多个值（输入字符串转化成列表）
        if type(value) == list or type(value) == int or type(value) == float:
            return value
        if value is None or len(value) == 0:
            return None
        value_list = []
        if value.startswith('[') and value.endswith(']'):
            for item in value[1:-1].split(','):
                item_strip = item.strip()
                if re.fullmatch(r'-?[0-9]*\.?[0-9]*', item_strip) is not None:  # 匹配为数字
                    if '.' in item_strip:
                        value_list.append(float(item_strip))
                    else:
                        value_list.append(int(item_strip))
                else:  # 字符串
                    value_list.append(item_strip[1:-1])
            return value_list
        else:
            return value

    @staticmethod
    def str2dict(value):  # 输入字符串转化成字典
        if type(value) == dict or type(value) == int or type(value) == float:
            return value
        if value is None or len(value) == 0:
            return None
        value_dict = {}
        if value.startswith('{') and value.endswith('}'):
            for item in value[1:-1].split(','):
                value_dict = ast.literal_eval(value)
            return value_dict
        else:
            return value

    @staticmethod
    def to_str(value):  # 输入转化成字符串
        if type(value) == int or type(value) == float:
            return value
        if value is None or len(value) == 0:
            return ""
        if type(value) == str:
            return value
        else:
            return str(value)

    @staticmethod
    def list_len(value):  # 返回输入列表的长度
        value2list = TextAssert.str2list(value)
        if type(value2list) != list:
            raise AssertionTypeNotExist('传入实际值({}) 不是列表格式'.format(value))
        else:
            return len(value2list)


class AssertionTypeNotExist(Exception):
    """断言类型错误"""
